﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Markup;
using System.Text;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Linq;
using System.Xml.Linq;
using System.Xml;
using System.Windows.Threading;
using System.IO.IsolatedStorage;
using System.Windows.Resources;
using System.Xml.Serialization;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Threading.Tasks;
using System.Threading;
using System.Windows.Media.Imaging;
using System.Reflection;

namespace Slex {
    /// <summary>
    /// 为代码构造xaml的能力扩展StringBuilder
    /// </summary>
    public static class Ex {
        #region timer
        public static void DelayPerformance(double milliseconds, Action<dynamic> task, dynamic taskparameter = default(dynamic)) {
            var dt = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(milliseconds) };
            dt.Tick += (o, k) => {
                try {
                    var timer = o as DispatcherTimer;
                    task.Invoke(taskparameter);
                    timer.Stop();
                } catch {
                    dt.Stop();
                }
            };
            dt.Start();
        }
        #endregion
        //
        #region VisualTreeHelper
        /// <summary>
        /// Defines if the specified element is inside the specified visual tree
        /// </summary>
        /// <param name="element"></param>
        /// <param name="treeRoot"></param>
        /// <returns></returns>
        public static bool IsInVisualTree(this DependencyObject element, DependencyObject treeRoot) {
            return element.GetVisualAncestors().Contains(treeRoot);
        }
        /// <summary>
        /// Indicates if the specified element is in the main Visual Tree
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public static bool IsInMainVisualTree(this DependencyObject element) {
#if SILVERLIGHT
            return IsInVisualTree(element, Application.Current.RootVisual);
#else
            return element.GetVisualAncestors().LastOrDefault() is Window;
#endif
        }
        /// <summary>
        /// Get visual ancestors of the specified element
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public static IEnumerable<DependencyObject> GetVisualAncestors(this DependencyObject element) {
            DependencyObject candidate = null;
            while (element != null) {
                candidate = VisualTreeHelper.GetParent(element);
                if (candidate == null) {
                    var asFe = element as FrameworkElement;
                    if (asFe != null)
                        candidate = asFe.Parent;
                }
                element = candidate;
                if (element != null)
                    yield return element;
            }
        }
        public static IEnumerable<DependencyObject> GetVisualDescendants(this DependencyObject element) {
            int childCount = VisualTreeHelper.GetChildrenCount(element);
            for (int i = 0; i < childCount; i++) {
                var child = VisualTreeHelper.GetChild(element, i);
                yield return child;
                foreach (var descendant in child.GetVisualDescendants()) {
                    yield return descendant;
                }
            }
        }
        //http://www.cnblogs.com/jv9/archive/2010/06/28/1766459.html
        public static T GetChildObject<T>(this DependencyObject obj, string name) where T : FrameworkElement {
            DependencyObject child = null;
            T grandChild = null;
            var count = VisualTreeHelper.GetChildrenCount(obj) - 1;
            for (int i = 0; i <= count; i++) {
                child = VisualTreeHelper.GetChild(obj, i);
                if (child is T && (((T)child).Name == name | string.IsNullOrEmpty(name))) {
                    return (T)child;
                } else {
                    grandChild = GetChildObject<T>(child, name);
                    if (grandChild != null)
                        return grandChild;
                }
            }
            return null;
        }
        public static List<FrameworkElement> GetChildObjects(this DependencyObject obj) {
            DependencyObject child = null;
            var childList = new List<FrameworkElement>();
            var count = VisualTreeHelper.GetChildrenCount(obj) - 1;
            for (int i = 0; i <= count; i++) {
                child = VisualTreeHelper.GetChild(obj, i);
                if (child is FrameworkElement)
                    childList.Add(child as FrameworkElement);
            }
            return childList;
        }
        public static T GetParentObject<T>(this DependencyObject obj, string name) where T : FrameworkElement {
            DependencyObject parent = VisualTreeHelper.GetParent(obj);
            while (parent != null) {
                if (parent is T && (((T)parent).Name == name | string.IsNullOrEmpty(name))) {
                    return (T)parent;
                }
                parent = VisualTreeHelper.GetParent(parent);
            }
            return null;
        }
        #endregion
        //
        #region StringBuilder
        /// <summary>
        /// 为xamlreader提供最简单的基本名称空间如果不提供 会报错
        /// </summary>
        /// <param name="sb"></param>
        /// <returns></returns>
        public static string GetDefaultNamespace {
            get {
                return "xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'";
            }
        }
        /// <summary>
        /// xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
        /// xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
        /// xmlns:mc='http://schemas.openxmlformats.org/markup-compatibility/2006'
        /// xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
        /// </summary>
        /// <param name="sb"></param>
        /// <returns></returns>
        public static string GetUsualNamespace {
            get {
                var sb = new StringBuilder();
                sb.AppendLine("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'");
                sb.AppendLine("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'");
                sb.AppendLine("xmlns:mc='http://schemas.openxmlformats.org/markup-compatibility/2006'");
                sb.AppendLine("xmlns:sdk='http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk'");
                sb.AppendLine();
                return sb.ToString();
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="pnamespace"></param>
        /// <param name="mark">名称空间自定义缩略名</param>
        /// <returns></returns>
        public static string GetNamespace(string assembly, string pnamespace, string mark) {
            return string.Format("xmlns:{0}='clr-namespace:{2}.{1};assembly={2}'", mark, pnamespace, assembly);
        }

        public static void SetText(this StringBuilder sb, string txt, int fontsize = 12, Brushs brush = Brushs.Black, FontWeight? fw = null, bool isbreak = true) {
            if (fw == null) fw = FontWeights.Normal;
            var lineend = isbreak ? "><LineBreak/>" : ">";
            var x = string.Format("{0}Run Foreground='{1}' FontSize='{2}' Text='{3}' FontWeight='{4}'/{5}", "<", brush.ToString(), fontsize, txt, fw, lineend);
            sb.AppendLine(x);
        }
        public static void SetLink(this StringBuilder sb, string txt, string uri = "", string target = "", string command = "", string param = "", int fontsize = 12, Brushs brush = Brushs.BlueViolet, FontWeight? fw = null, bool isbreak = false) {                        
            var x1 = string.Format("Binding {0}",command);
            var x2 = string.Format("Binding {0}",param);
            var x3 = uri;
            var starttag = "<Hyperlink Command='__x1' CommandParameter='__x2' NavigateUri='__x3' TargetName='__x4'>";
            starttag = starttag.Replace("__x1", "{" + x1 + "}");
            starttag = starttag.Replace("__x2", "{" + x2 + "}");
            starttag = starttag.Replace("__x3", x3);
            starttag = starttag.Replace("__x4", string.IsNullOrEmpty(target)?"_blank":target);
            var endtag = "</Hyperlink{0}";
            if (fw == null) fw = FontWeights.Normal;
            var lineend = isbreak ? "><LineBreak/>" : ">";
            var x = string.Format("{0}Run Foreground='{1}' FontSize='{2}' Text='{3}' FontWeight='{4}'/{5}", "<", brush.ToString(), fontsize, txt, fw, ">");
            sb.Append(starttag);
            sb.Append(x);
            sb.AppendFormat(endtag,lineend);
        }

        public static void StartTag(this StringBuilder sb, string tag="Paragraph", bool isroot = false,string ns="") {
            if (isroot) {
                var fm = "<" + tag + " {0}>";
                var namespaces=string.IsNullOrEmpty(ns)?GetDefaultNamespace:ns;
                sb.AppendFormat(fm, namespaces);
                sb.AppendLine();
            } else {
                sb.AppendLine("<" + tag + ">");
            }
        }
        public static void EndTag(this StringBuilder sb, string tag = "Paragraph") {
            sb.AppendLine("</" + tag + ">");
        }
        public static T ToXamlType<T>(this StringBuilder sb) where T : class {
            T t = default(T);
            var data = sb.ToString(0, sb.Length);
            t = XamlReader.Load(data) as T;
            sb.Clear();
            return t;
        }
        #endregion
        //
        #region path
        public static void DrawFun(this System.Windows.Shapes.Path path, Func<double, double> func, double count = 1000, double startx = 0.0, double starty
= 0.0) {
            var pf = new PathFigure { StartPoint = new Point(startx, starty) };
            for (int i = 0; i < count; i++) {
                pf.Segments.Add(new LineSegment { Point = new Point(i + startx, func.Invoke(i) + starty) });
            }
            var pg = new PathGeometry { };
            pg.Figures.Add(pf);
            path.Data = pg;
        }
        public static void DrawFunAnimate(this System.Windows.Shapes.Path path, Func<double, double> func, double count = 1000, double startx = 0.0, double starty = 0.0, double interval = 500) {
            var pf = new PathFigure { StartPoint = new Point(startx, starty) };
            var pg = new PathGeometry { };
            pg.Figures.Add(pf);
            path.Data = pg;
            int i = 0;
            var dt = new System.Windows.Threading.DispatcherTimer {
                Interval = TimeSpan.FromMilliseconds(interval),
            };
            dt.Tick += (o, k) => {
                if (i < count) {
                    pf.Segments.Add(new LineSegment { Point = new Point(i + startx, func.Invoke(i) + starty) });
                    i++;
                } else {
                    dt.Stop();
                }
            };
            dt.Start();
        }

        public static void DrawFunAnimate(this System.Windows.Shapes.Path path, Func<double, double> func, double count = 1000, double startx = 0.0, double starty = 0.0) {
            var pf = new PathFigure { StartPoint = new Point(startx, starty) };
            var pg = new PathGeometry { };
            pg.Figures.Add(pf);
            path.Data = pg;
            int i = 0;
            EventHandler xx = null;
            xx = (o, k) => {
                if (i < count) {
                    pf.Segments.Add(new LineSegment { Point = new Point(i + startx, func.Invoke(i) + starty) });
                    i++;
                } else {
                    CompositionTarget.Rendering -= xx;
                }
            };
            CompositionTarget.Rendering += xx;
        }
        public static void DrawFunAnimate(this System.Windows.Shapes.Path path, Func<double, double> func, Storyboard sb, double count = 1000, double startx = 0.0, double starty = 0.0) {
            var pf = new PathFigure { StartPoint = new Point(startx, starty) };
            var pg = new PathGeometry();
            pg.Figures.Add(pf);
            path.Data = pg;
            int i = 0;
            EventHandler xx = null;
            xx = (o, k) => {
                if (i < count) {
                    pf.Segments.Add(new LineSegment { Point = new Point(i + startx, func.Invoke(i) + starty) });
                    i++;
                } else {
                    sb.Stop();
                }
            };
            sb.Completed += xx;
            sb.Begin();
        }

        public static void DrawCustomLineSegment(this System.Windows.Shapes.Path path, params Point[] ps) {
            var pf = new PathFigure { };
            pf.StartPoint = ps[0];
            var length = ps.Length;
            for (int i = 1; i < length; i++) {
                pf.Segments.Add(new LineSegment { Point = ps[i] });
            }
            var pg = new PathGeometry { };
            pg.Figures.Add(pf);
            path.Data = pg;
        }
        public static void ClearParentOfCanvas(this System.Windows.Shapes.Path path) {
            if (path.Parent != null && path.Parent as Canvas != null) {
                var p = path.Parent as Canvas;
                p.Children.Remove(path);
            }
        }
        public static void SetPathData(this System.Windows.Shapes.Path path, string mini) {
            var sb = new StringBuilder();
            sb.AppendFormat("<Path {0} Data='{1}'/>", GetDefaultNamespace, mini);
            var pathvalue = sb.ToXamlType<System.Windows.Shapes.Path>();
            var geometry = pathvalue.Data;
            //pathvalue.ClearValue(Path.DataProperty);
            pathvalue.Data = null;
            path.Data = geometry;
        }
        #endregion
        //
        #region brushs
        public static int GetCount(this Brushs b) {
            return fColorfs.Count;
        }
        public static int GetIndex(this Brushs b) {
            return fColorfs.IndexOf(fColorfs.Single(c => c.ColorName == b.ToString()));
        }
        public static SolidColorBrush ToBrush(this Brushs b) {
            foreach (var item in fColorfs) {
                if (item.ColorName == b.ToString()) {
                    return new SolidColorBrush(item.ColorValue.ToColor());
                }
            }
            return null;
        }
        private static Color ToColor(this string colorName) {
            if (colorName.StartsWith("#"))
                colorName = colorName.Replace("#", string.Empty);
            int v = int.Parse(colorName, System.Globalization.NumberStyles.HexNumber);
            return new Color() {
                A = Convert.ToByte((v >> 24) & 255),
                R = Convert.ToByte((v >> 16) & 255),
                G = Convert.ToByte((v >> 8) & 255),
                B = Convert.ToByte((v >> 0) & 255)
            };
        }
        public static Color ToColor(this Brushs brush) {
            var name = brush.ToString();
            var value = fColorfs.Single(c => c.ColorName == name);
            return value.ColorValue.ToColor();
        }
        static List<Colorf> fColorfs = Properties.Resource.ColorTable.JsonDeserialise<List<Colorf>>();
        #endregion
        //
        #region line and area
        /// <summary>
        /// 对points的解释方式 有两种基于点集的，和基于偏移量的，前者points[0]为一个数后者为非数'p'
        /// </summary>
        /// <param name="p"></param>
        /// <param name="b"></param>
        /// <param name="points"></param>
        /// <param name="isArea"></param>
        /// <returns></returns>
        public static void SetPolyline(this Panel p, Brushs b, string points, bool isArea = false) {
            System.Windows.Shapes.Polyline line = null;
            if (!string.IsNullOrEmpty(points)) {
                if (isArea)
                    line = new System.Windows.Shapes.Polyline { Fill = b.ToBrush() };
                else
                    line = new System.Windows.Shapes.Polyline { Stroke = b.ToBrush() };
                var mark = points[0];
                if (mark != 'p') {
                    var _points = points.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (var item in _points) {
                        var v1 = item.Split(',');
                        if (v1.Length != 2) throw new Exception("points 语法错误，空格分割的是数对由逗号分开");
                        line.Points.Add(new Point(double.Parse(v1[0]), double.Parse(v1[1])));
                    }
                } else {
                    var length = points.Length;
                    var _points = points.Substring(1).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    var original = _points[0].Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    if (original.Length != 2) throw new Exception("初始点定义错误");
                    var x = double.Parse(original[0]);
                    var y = double.Parse(original[1]);
                    line.Points.Add(new Point(x, y));
                    var count = _points.Length;
                    for (int i = 1; i < count; i++) {
                        var offestx = double.Parse(_points[i].Split(',')[0]);
                        var offesty = double.Parse(_points[i].Split(',')[1]);
                        line.Points.Add(new Point(x + offestx, y + offesty));
                        x += offestx;
                        y += offesty;
                    }
                }
            }
            p.Children.Add(line);
        }
        public static void SetPolygon(this Panel panel, Brushs b, string points, bool isArea = false) {
            System.Windows.Shapes.Polygon line = null;
            if (!string.IsNullOrEmpty(points)) {
                if (isArea)
                    line = new System.Windows.Shapes.Polygon { Fill = b.ToBrush() };
                else
                    line = new System.Windows.Shapes.Polygon { Stroke = b.ToBrush() };
                var mark = points[0];
                if (mark != 'p') {
                    var _points = points.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (var item in _points) {
                        var v1 = item.Split(',');
                        if (v1.Length != 2) throw new Exception("points 语法错误，空格分割的是数对由逗号分开");
                        line.Points.Add(new Point(double.Parse(v1[0]), double.Parse(v1[1])));
                    }
                } else {
                    var length = points.Length;
                    var _points = points.Substring(1).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    var original = _points[0].Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    if (original.Length != 2) throw new Exception("初始点定义错误");
                    var x = double.Parse(original[0]);
                    var y = double.Parse(original[1]);
                    line.Points.Add(new Point(x, y));
                    var count = _points.Length;
                    for (int i = 1; i < count; i++) {
                        var offestx = double.Parse(_points[i].Split(',')[0]);
                        var offesty = double.Parse(_points[i].Split(',')[1]);
                        line.Points.Add(new Point(x + offestx, y + offesty));
                        x += offestx;
                        y += offesty;
                    }
                }
            }
            panel.Children.Add(line);
        }

        public static void SetData(this Polyline line, Brushs b, string points, bool isArea = false) {
            if (isArea)
                line.Fill = b.ToBrush();
            else
                line.Stroke = b.ToBrush();
            var mark = points[0];
            if (mark != 'p') {
                line.Points.Clear();
                var _points = points.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var item in _points) {
                    var v1 = item.Split(',');
                    if (v1.Length != 2) throw new Exception("points 语法错误，空格分割的是数对由逗号分开");
                    line.Points.Add(new Point(double.Parse(v1[0]), double.Parse(v1[1])));
                }
            } else {
                line.Points.Clear();
                var length = points.Length;
                var _points = points.Substring(1).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                var original = _points[0].Split(',');
                if (original.Length != 2) throw new Exception("初始点定义错误");
                var x = double.Parse(original[0]);
                var y = double.Parse(original[1]);
                line.Points.Add(new Point(x, y));
                var count = _points.Length;
                for (int i = 1; i < count; i++) {
                    var offestx = double.Parse(_points[i].Split(',')[0]);
                    var offesty = double.Parse(_points[i].Split(',')[1]);
                    line.Points.Add(new Point(x + offestx, y + offesty));
                    x += offestx;
                    y += offesty;
                }
            }

        }
        public static void SetData(this Polygon line, Brushs b, string points, bool isArea = false) {
            if (isArea)
                line.Fill = b.ToBrush();
            else
                line.Stroke = b.ToBrush();
            var mark = points[0];
            if (mark != 'p') {
                line.Points.Clear();
                var _points = points.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var item in _points) {
                    var v1 = item.Split(',');
                    if (v1.Length != 2) throw new Exception("points 语法错误，空格分割的是数对由逗号分开");
                    line.Points.Add(new Point(double.Parse(v1[0]), double.Parse(v1[1])));
                }
            } else {
                line.Points.Clear();
                var length = points.Length;
                var _points = points.Substring(1).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                var original = _points[0].Split(',');
                if (original.Length != 2) throw new Exception("初始点定义错误");
                var x = double.Parse(original[0]);
                var y = double.Parse(original[1]);
                line.Points.Add(new Point(x, y));
                var count = _points.Length;
                for (int i = 1; i < count; i++) {
                    var offestx = double.Parse(_points[i].Split(',')[0]);
                    var offesty = double.Parse(_points[i].Split(',')[1]);
                    line.Points.Add(new Point(x + offestx, y + offesty));
                    x += offestx;
                    y += offesty;
                }
            }
        }
        #endregion
        //
        #region wait window
        /// <summary>
        /// 进度条
        /// <param name="g">接受扩展的Panel</param>
        /// <param name="msg">处理完成后要提示的内容</param>
        /// </summary>
        public static void SetWaitWindow(this Panel g, string msg = "", double waittime = 5000) {
            if (fBusyIndicator != null) {
                g.Children.Remove(fBusyIndicator);
                fBusyIndicator = null;
            }
            var bi = new BusyIndicator { Foreground = new SolidColorBrush(Colors.Black) };
            //加入逻辑当传msg不为""时启动自检
            var msgIsEmpty = string.IsNullOrEmpty(msg);
            bi.BusyContent = "正在等待反馈...";
            bi.IsBusy = true;
            fBusyIndicator = bi;
            g.Children.Add(bi);
            if (!msgIsEmpty) {
                bi.Tag = msg;
            } else {
                bi.Tag = null;
            }
            //自检时间为超过5秒则自动关闭，关闭前作提示。
            DelayPerformance(waittime, d => {
                var sp = new StackPanel { Orientation = Orientation.Horizontal };
                var hlb = new HyperlinkButton { Content = "X", Margin = new Thickness(20, -5, 0, 0), HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center };
                hlb.Click += (o, k) => {
                    g.Children.Remove(bi);
                    g.Children.Remove(fBusyIndicator);
                    fBusyIndicator = null;
                    bi = null;
                };
                var tbmsg = new TextBlock { Text = "反馈延时,无响应！" };
                sp.Children.Add(tbmsg);
                sp.Children.Add(hlb);
                bi.BusyContent = sp;
                DelayPerformance(700, dd => {
                    g.Children.Remove(fBusyIndicator);
                    fBusyIndicator = null;
                });
            });
        }
        //current BusyIndicator
        static BusyIndicator fBusyIndicator;
        public static void CloseWaitWindow(this Panel panel) {
            if (fBusyIndicator != null) {
                var panel2 = fBusyIndicator.Parent as Panel;
                if (panel.Equals(panel2))
                    if (fBusyIndicator.Tag != null) {
                        fBusyIndicator.BusyContent = fBusyIndicator.Tag.ToString();
                        DelayPerformance(700, d => {
                            panel.Children.Remove(fBusyIndicator);
                            fBusyIndicator = null;
                        });
                    } else {
                        panel.Children.Remove(fBusyIndicator);
                        fBusyIndicator = null;
                    }
            }
        }
        #endregion
        //
        #region logic manager
        static Dictionary<string, Action<dynamic, dynamic>> fExLogic;
        public static void BuildLogic(string key, Action<dynamic, dynamic> logic) {
            if (fExLogic == null) fExLogic = new Dictionary<string, Action<dynamic, dynamic>>();
            lock (lockobj) {
                if (fPathEnsure) {
                    if (!fExLogic.Keys.Contains(key) && fExLogic.Count <= 100) {
                        fExLogic.Add(key, logic);
                        fPathEnsure = false;
                    } else if (fExLogic.Count > 100) {
                        fExLogic.Clear();
                    }
                }
            }
        }
        public static void DeployLogic(dynamic sender, dynamic arg, bool lastInvoker = false) {
            var v1 = new System.Diagnostics.StackTrace();
            var v2 = v1.GetFrame(1).GetMethod();
            var v3 = v2.Name;
            var v4 = v2.DeclaringType.Name;
            if (!lastInvoker) {
                var v5 = string.Join(".", fInvokeNumber, v4, v3);
                foreach (var item in fExLogic) {
                    if (v5 == item.Key) {
                        fExLogic[v5].Invoke(sender, arg);
                        break;
                    }
                }
            } else {
                var v6 = string.Join(".", v4, v3);
                var v7 = from key in fExLogic.Keys where key.Substring(2, key.Length - 2) == v6 select key;
                if (v7.Count() > 0) {
                    var v8 = v7.Max(key => int.Parse(key.Split('.')[0]));
                    var v9 = string.Join(".", v8, v6);
                    fExLogic[v9].Invoke(sender, arg);
                }
            }
        }
        static volatile int fInvokeNumber;
        static volatile bool fPathEnsure = false;
        static object lockobj = new object();
        public static string SetLogicKey(object labtarget, string methodname, int invokenumber) {
            lock (lockobj) {
                fInvokeNumber = invokenumber;
                var v1 = labtarget.GetType().Name;
                fPathEnsure = true;
                return string.Join(".", fInvokeNumber, v1, methodname);
            }
        }
        public static void ClearLogic() {
            fExLogic.Clear();
        }
        #endregion
        //
        #region test things
        public static void WriteLog(this TextBlock tb, string s, Brushs b = Brushs.DarkBlue) {
            if (s[0] == '-')
                tb.Inlines.Insert(0, new Run { Foreground = b.ToBrush(), Text = string.Format("{0} {1} {2}", Environment.NewLine, ">>", s.Substring(1)) });
            else
                tb.Inlines.Add(new Run { Foreground = b.ToBrush(), Text = string.Format("{0} {1} {2}", Environment.NewLine, ">>", s) });

        }
        public static void ShowCase(this Grid g, params FrameworkElement[] fes) {
            foreach (var item in fes) {
                if (item == null) continue;
                if (item.Parent != null && item.Parent is Panel) {
                    ((Panel)item.Parent).Children.Remove(item);
                }
                g.Children.Add(item);
            }
        }
        #endregion
        //
        #region about xap res
        static Assembly LoadAssemblyFromXap(Stream packageStream, string dllName) {
            var uri = new Uri(dllName, UriKind.Relative);
            var xapPackageSri = new StreamResourceInfo(packageStream, null);
            var assemblySri = Application.GetResourceStream(xapPackageSri, uri);
            var assemblyPart = new AssemblyPart();
            var assembly = assemblyPart.Load(assemblySri.Stream);
            return assembly;
        }
        /// <summary>
        /// 从指定xap中加载指定dll所指定的程序集(assembly)
        /// </summary>
        /// <param name="xapname">xap不带后缀名</param>
        /// <param name="dllName">dllName 不带后缀名</param>
        /// <param name="carryback">加载成功后的回调</param>
        public static void LoadAssemblyByXap(string xapname, string dllName, Action<Assembly> carryback) {
            var wc = new WebClient();
            wc.OpenReadCompleted += (s, e) => {
                carryback.Invoke(LoadAssemblyFromXap(e.Result, dllName + ".dll"));
            };
            wc.OpenReadAsync(new Uri(xapname + ".xap", UriKind.Relative));
        }
        /// <summary>
        /// 加载指定xap包的指定FramworkElement,注意本方法暗含取与xap同名的dll
        /// </summary>
        /// <param name="xapname">串不包括'.xap'后缀</param>
        /// <param name="frameworkelementpath">若有子目录结构需要写上，以作为路径表达的一部分</param>
        /// <param name="carryback"></param>
        public static void LoadContentByXap(string xapname, string frameworkelementpath, Action<dynamic> carryback) {
            var wc = new WebClient();
            wc.OpenReadCompleted += (s, e) => {
                var vv = new StreamResourceInfo(e.Result, "application/binary");
                AssemblyPart ap = new AssemblyPart();
                var assembly = ap.Load(Application.GetResourceStream(vv, new Uri(xapname + ".dll", UriKind.Relative)).Stream);
                var content = assembly.CreateInstance(xapname + "." + frameworkelementpath);
                if (carryback != null) {
                    carryback.Invoke(content);
                }
            };
            wc.OpenReadAsync(new Uri(xapname + ".xap", UriKind.Relative));
        }
        /// <summary>
        /// mef parts load by xaps
        /// </summary>
        /// <param name="mefhost">包含import定义 的对象</param>
        /// <param name="Do">xaps下载完成以后要做的</param>
        /// <param name="xapnames">带.xap后缀名的xap包 在ClientBin目录下的全名称</param>
        public static void LoadPartsByXaps(this object mefhost, Action Do, params string[] xapnames) {
            var ac = new AggregateCatalog();
            var asc = new AssemblyCatalog(mefhost.GetType().Assembly);
            var dcs = new List<DeploymentCatalog>();
            foreach (var item in xapnames) {
                dcs.Add(new DeploymentCatalog(item));
            }
            ac.Catalogs.Add(asc);
            var sc = SynchronizationContext.Current;
            var tasks = new List<Task>();
            var taskcc = Task.Factory.StartNew(() => {
                sc.Send(sopc => {
                    foreach (DeploymentCatalog item in dcs) {
                        var task = new Task(x => { ac.Catalogs.Add(item); }, null);
                        tasks.Add(task);
                        item.DownloadCompleted += (o, k) => {
                            task.Start();
                        };
                        item.DownloadAsync();
                    }
                }, null);
            });
            var taskend = taskcc.ContinueWith(x => {
                Task.WaitAll(tasks.ToArray());
            });
            taskend.ContinueWith(x => {
                try {
                    sc.Post(sopc => {
                        var cc = new CompositionContainer(ac);
                        cc.ComposeParts(mefhost);
                        Do.Invoke();
                    }, null);
                } catch (Exception e) {
                    MessageBox.Show(e.Message);
                }
            });
        }
        #endregion
        //
        #region isolated storage
        public static void WriteToIsolatedStorage(string fpath, bool isapp, byte[] content) {
            if (isapp) {
                using (var v = IsolatedStorageFile.GetUserStoreForApplication()) {
                    var v2 = v.OpenFile(fpath, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write);
                    v2.Write(content, 0, content.Length);
                }
            } else {
                using (var v = IsolatedStorageFile.GetUserStoreForSite()) {
                    var v2 = v.OpenFile(fpath, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write);
                    v2.Write(content, 0, content.Length);
                }
            }
        }
        public static byte[] ReadFormIsolatedStorage(string fpath, bool isapp) {
            byte[] r = default(byte[]);
            try {
                if (isapp) {
                    using (var v = IsolatedStorageFile.GetUserStoreForApplication()) {
                        var v2 = v.OpenFile(fpath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
                        r = new byte[v2.Length];
                        v2.Read(r, 0, (int)v2.Length);
                    }
                } else {
                    using (var v = IsolatedStorageFile.GetUserStoreForSite()) {
                        var v2 = v.OpenFile(fpath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
                        r = new byte[v2.Length];
                        v2.Read(r, 0, (int)v2.Length);
                    }
                }
            } catch (Exception e) {
                MessageBox.Show(e.Message, "title", MessageBoxButton.OK);
            }
            return r;
        }
        public static void ClearIsolatedStorage(bool isapp) {
            if (isapp) {
                using (var v = IsolatedStorageFile.GetUserStoreForApplication()) {
                    v.Remove();
                }
            } else {
                using (var v = IsolatedStorageFile.GetUserStoreForSite()) {
                    v.Remove();
                }
            }
        }
        public static void DeletFile(string fpath, bool isapp) {
            if (isapp) {
                using (var v = IsolatedStorageFile.GetUserStoreForApplication()) {
                    if (v.FileExists(fpath))
                        v.DeleteFile(fpath);
                }
            } else {
                using (var v = IsolatedStorageFile.GetUserStoreForSite()) {
                    if (v.FileExists(fpath))
                        v.DeleteFile(fpath);
                }
            }
        }
        #endregion
        //
        #region writeable bitmap
        //   特别鸣谢，此算法提供者: rene.schulte --端纳.舒尔特! thx for rene.schulte
        //   Description:       Collection of extension methods for the Silverlight WriteableBitmap class.
        //
        //   Changed by:        $Author: rene.schulte $
        //   Changed on:        $Date: 2009-11-11 21:41:53 +0100 (Mi, 11. Nov 2009) $
        //   Changed in:        $Revision: 63 $
        //   Project:           $URL: file:///U:/Data/Development/SVN/SilverlightDemos/trunk/WriteableBmpSample/WriteableBmpSample/WriteableBitmapExtensions.cs $
        //   Id:                $Id: WriteableBitmapExtensions.cs 63 2009-11-11 20:41:53Z rene.schulte $
        //
        //
        //   Copyright (c) 2009 Rene Schulte
        //
        //   This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License 
        //   as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
        //   This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
        //   without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
        //   See the GNU General Public License for more details.
        //   You should have received a copy of the GNU General Public License along with this program; ("License.txt").
        //   if not, see <http://www.gnu.org/licenses/>. 
        //

        private const float PreMultiplyFactor = 1 / 255f;

        /// <summary>
        /// Fills the whole WriteableBitmap with a color.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="color">The color used for filling.</param>
        public static void Clear(this WriteableBitmap bmp, Color color) {
            int col = (color.A << 24) | (color.R << 16) | (color.G << 8) | color.B;
            int[] pixels = bmp.Pixels;
            int pixelCount = pixels.Length;
            for (int i = 0; i < pixelCount; i++) {
                pixels[i] = col;
            }
        }

        /// <summary>
        /// Fills the whole WriteableBitmap with an empty color (0).
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        public static void Clear(this WriteableBitmap bmp) {
            Array.Clear(bmp.Pixels, 0, bmp.Pixels.Length);
        }


        #region DrawLine

        /// <summary>
        /// Draws a colored line by connecting two points using a DDA algorithm (Digital Differential Analyzer).
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x1">The x-coordinate of the start point.</param>
        /// <param name="y1">The y-coordinate of the start point.</param>
        /// <param name="x2">The x-coordinate of the end point.</param>
        /// <param name="y2">The y-coordinate of the end point.</param>
        /// <param name="color">The color for the line.</param>
        public static void DrawLineDDA(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, Color color) {
            bmp.DrawLineDDA(x1, y1, x2, y2, (color.A << 24) | (color.R << 16) | (color.G << 8) | color.B);
        }

        /// <summary>
        /// Draws a colored line by connecting two points using a DDA algorithm (Digital Differential Analyzer).
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x1">The x-coordinate of the start point.</param>
        /// <param name="y1">The y-coordinate of the start point.</param>
        /// <param name="x2">The x-coordinate of the end point.</param>
        /// <param name="y2">The y-coordinate of the end point.</param>
        /// <param name="color">The color for the line.</param>
        public static void DrawLineDDA(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int color) {
            // Use refs for faster access (really important!) speeds up a lot!
            int w = bmp.PixelWidth;
            int[] pixels = bmp.Pixels;

            // Distance start and end point
            int dx = x2 - x1;
            int dy = y2 - y1;

            // Determine slope (absoulte value)
            int len = dy >= 0 ? dy : -dy;
            int lenx = dx >= 0 ? dx : -dx;
            if (lenx > len) {
                len = lenx;
            }

            // Prevent divison by zero
            if (len != 0) {
                // Init steps and start
                float incx = dx / (float)len;
                float incy = dy / (float)len;
                float x = x1;
                float y = y1;

                // Walk the line!
                for (int i = 0; i < len; i++) {
                    pixels[(int)y * w + (int)x] = color;
                    x += incx;
                    y += incy;
                }
            }
        }

        /// <summary>
        /// Draws a colored line by connecting two points using an optimized DDA by Nikola 
        /// (http://nokola.com/blog/post/2009/11/06/Faster-DrawLine%28%29-in-Silverlight-%28400000-linessec%29.aspx).
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x1">The x-coordinate of the start point.</param>
        /// <param name="y1">The y-coordinate of the start point.</param>
        /// <param name="x2">The x-coordinate of the end point.</param>
        /// <param name="y2">The y-coordinate of the end point.</param>
        /// <param name="color">The color for the line.</param>
        public static void DrawLine(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, Color color) {
            bmp.DrawLine(x1, y1, x2, y2, (color.A << 24) | (color.R << 16) | (color.G << 8) | color.B);
        }

        /// <summary>
        /// Draws a colored line by connecting two points using an optimized DDA by Nikola 
        /// (http://nokola.com/blog/post/2009/11/06/Faster-DrawLine%28%29-in-Silverlight-%28400000-linessec%29.aspx).
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x1">The x-coordinate of the start point.</param>
        /// <param name="y1">The y-coordinate of the start point.</param>
        /// <param name="x2">The x-coordinate of the end point.</param>
        /// <param name="y2">The y-coordinate of the end point.</param>
        /// <param name="color">The color for the line.</param>
        public static void DrawLine(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int color) {
            // Use refs for faster access (really important!) speeds up a lot!
            int w = bmp.PixelWidth;
            int[] pixels = bmp.Pixels;

            // Distance start and end point
            int dx = x2 - x1;
            int dy = y2 - y1;

            const int PRECISION_SHIFT = 8;
            const int PRECISION_VALUE = 1 << PRECISION_SHIFT;

            // Determine slope (absoulte value)
            int lenX, lenY;
            int incy1;
            if (dy >= 0) {
                incy1 = PRECISION_VALUE;
                lenY = dy;
            } else {
                incy1 = -PRECISION_VALUE;
                lenY = -dy;
            }

            int incx1;
            if (dx >= 0) {
                incx1 = 1;
                lenX = dx;
            } else {
                incx1 = -1;
                lenX = -dx;
            }

            if (lenX > lenY) { // x increases by +/- 1
                // Init steps and start
                int incy = (dy << PRECISION_SHIFT) / lenX;
                int y = y1 << PRECISION_SHIFT;

                // Walk the line!
                for (int i = 0; i < lenX; i++) {
                    pixels[(y >> PRECISION_SHIFT) * w + x1] = color;
                    x1 += incx1;
                    y += incy;
                }
            } else { // since y increases by +/-1, we can safely add (*h) before the for() loop, since there is no fractional value for y
                // Prevent divison by zero
                if (lenY == 0) {
                    return;
                }

                // Init steps and start
                int incx = (dx << PRECISION_SHIFT) / lenY;
                int index = (x1 + y1 * w) << PRECISION_SHIFT;

                // Walk the line!
                int inc = incy1 * w + incx;
                for (int i = 0; i < lenY; i++) {
                    pixels[index >> PRECISION_SHIFT] = color;
                    index += inc;
                }
            }
        }

        /// <summary>
        /// Draws a colored line by connecting two points using the Bresenham algorithm.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x1">The x-coordinate of the start point.</param>
        /// <param name="y1">The y-coordinate of the start point.</param>
        /// <param name="x2">The x-coordinate of the end point.</param>
        /// <param name="y2">The y-coordinate of the end point.</param>
        /// <param name="color">The color for the line.</param>
        public static void DrawLineBresenham(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int color) {
            // Use refs for faster access (really important!) speeds up a lot!
            int w = bmp.PixelWidth;
            int[] pixels = bmp.Pixels;

            // Distance start and end point
            int dx = x2 - x1;
            int dy = y2 - y1;

            // Determine sign for direction x
            int incx = 0;
            if (dx < 0) {
                dx = -dx;
                incx = -1;
            } else if (dx > 0) {
                incx = 1;
            }

            // Determine sign for direction y
            int incy = 0;
            if (dy < 0) {
                dy = -dy;
                incy = -1;
            } else if (dy > 0) {
                incy = 1;
            }

            // Which gradient is larger
            int pdx, pdy, odx, ody, es, el;
            if (dx > dy) {
                pdx = incx;
                pdy = 0;
                odx = incx;
                ody = incy;
                es = dy;
                el = dx;
            } else {
                pdx = 0;
                pdy = incy;
                odx = incx;
                ody = incy;
                es = dx;
                el = dy;
            }

            // Init start
            int x = x1;
            int y = y1;
            int error = el >> 1;
            pixels[y * w + x] = color;

            // Walk the line!
            for (int i = 0; i < el; i++) {
                // Update error term
                error -= es;

                // Decide which coord to use
                if (error < 0) {
                    error += el;
                    x += odx;
                    y += ody;
                } else {
                    x += pdx;
                    y += pdy;
                }

                // Set pixel
                pixels[y * w + x] = color;
            }
        }

        #endregion

        #region Draw Shapes

        /// <summary>
        /// Draws a polyline. Add the first point also at the end of the array if the line should be closed.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="points">The points of the polyline in x and y pairs, therefore the array is interpreted as (x1, y1, x2, y2, ..., xn, yn).</param>
        /// <param name="color">The color for the line.</param>
        public static void DrawPolyline(this WriteableBitmap bmp, int[] points, Color color) {
            bmp.DrawPolyline(points, (color.A << 24) | (color.R << 16) | (color.G << 8) | color.B);
        }

        /// <summary>
        /// Draws a polyline. Add the first point also at the end of the array if the line should be closed.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="points">The points of the polyline in x and y pairs, therefore the array is interpreted as (x1, y1, x2, y2, ..., xn, yn).</param>
        /// <param name="color">The color for the line.</param>
        public static void DrawPolyline(this WriteableBitmap bmp, int[] points, int color) {
            int x1 = points[0];
            int y1 = points[1];
            int x2, y2;
            for (int i = 2; i < points.Length; i += 2) {
                x2 = points[i];
                y2 = points[i + 1];
                bmp.DrawLine(x1, y1, x2, y2, color);
                x1 = x2;
                y1 = y2;
            }
        }

        /// <summary>
        /// Draws a triangle.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x1">The x-coordinate of the 1st point.</param>
        /// <param name="y1">The y-coordinate of the 1st point.</param>
        /// <param name="x2">The x-coordinate of the 2nd point.</param>
        /// <param name="y2">The y-coordinate of the 2nd point.</param>
        /// <param name="x3">The x-coordinate of the 3rd point.</param>
        /// <param name="y3">The y-coordinate of the 3rd point.</param>
        /// <param name="color">The color.</param>
        public static void DrawTriangle(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int x3, int y3, Color color) {
            bmp.DrawTriangle(x1, y1, x2, y2, x3, y3, (color.A << 24) | (color.R << 16) | (color.G << 8) | color.B);
        }

        /// <summary>
        /// Draws a triangle.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x1">The x-coordinate of the 1st point.</param>
        /// <param name="y1">The y-coordinate of the 1st point.</param>
        /// <param name="x2">The x-coordinate of the 2nd point.</param>
        /// <param name="y2">The y-coordinate of the 2nd point.</param>
        /// <param name="x3">The x-coordinate of the 3rd point.</param>
        /// <param name="y3">The y-coordinate of the 3rd point.</param>
        /// <param name="color">The color.</param>
        public static void DrawTriangle(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int x3, int y3, int color) {
            bmp.DrawLine(x1, y1, x2, y2, color);
            bmp.DrawLine(x2, y2, x3, y3, color);
            bmp.DrawLine(x3, y3, x1, y1, color);
        }

        /// <summary>
        /// Draws a quad.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x1">The x-coordinate of the 1st point.</param>
        /// <param name="y1">The y-coordinate of the 1st point.</param>
        /// <param name="x2">The x-coordinate of the 2nd point.</param>
        /// <param name="y2">The y-coordinate of the 2nd point.</param>
        /// <param name="x3">The x-coordinate of the 3rd point.</param>
        /// <param name="y3">The y-coordinate of the 3rd point.</param>
        /// <param name="x4">The x-coordinate of the 4th point.</param>
        /// <param name="y4">The y-coordinate of the 4th point.</param>
        /// <param name="color">The color.</param>
        public static void DrawQuad(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, Color color) {
            bmp.DrawQuad(x1, y1, x2, y2, x3, y3, x4, y4, (color.A << 24) | (color.R << 16) | (color.G << 8) | color.B);
        }

        /// <summary>
        /// Draws a quad.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x1">The x-coordinate of the 1st point.</param>
        /// <param name="y1">The y-coordinate of the 1st point.</param>
        /// <param name="x2">The x-coordinate of the 2nd point.</param>
        /// <param name="y2">The y-coordinate of the 2nd point.</param>
        /// <param name="x3">The x-coordinate of the 3rd point.</param>
        /// <param name="y3">The y-coordinate of the 3rd point.</param>
        /// <param name="x4">The x-coordinate of the 4th point.</param>
        /// <param name="y4">The y-coordinate of the 4th point.</param>
        /// <param name="color">The color.</param>
        public static void DrawQuad(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int color) {
            bmp.DrawLine(x1, y1, x2, y2, color);
            bmp.DrawLine(x2, y2, x3, y3, color);
            bmp.DrawLine(x3, y3, x4, y4, color);
            bmp.DrawLine(x4, y4, x1, y1, color);
        }

        /// <summary>
        /// Draws a rectangle.
        /// x2 has to be greater than x1 and y2 has to be greater than y1.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x1">The x-coordinate of the bounding rectangle's left side.</param>
        /// <param name="y1">The y-coordinate of the bounding rectangle's top side.</param>
        /// <param name="x2">The x-coordinate of the bounding rectangle's right side.</param>
        /// <param name="y2">The y-coordinate of the bounding rectangle's bottom side.</param>
        /// <param name="color">The color.</param>
        public static void DrawRectangle(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, Color color) {
            bmp.DrawRectangle(x1, y1, x2, y2, (color.A << 24) | (color.R << 16) | (color.G << 8) | color.B);
        }

        /// <summary>
        /// Draws a rectangle.
        /// x2 has to be greater than x1 and y2 has to be greater than y1.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x1">The x-coordinate of the bounding rectangle's left side.</param>
        /// <param name="y1">The y-coordinate of the bounding rectangle's top side.</param>
        /// <param name="x2">The x-coordinate of the bounding rectangle's right side.</param>
        /// <param name="y2">The y-coordinate of the bounding rectangle's bottom side.</param>
        /// <param name="color">The color.</param>
        public static void DrawRectangle(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int color) {
            // Use refs for faster access (really important!) speeds up a lot!
            int w = bmp.PixelWidth;
            int[] pixels = bmp.Pixels;

            int startY = y1 * w;
            int endY = y2 * w;

            int offset2 = endY + x1;
            int endOffset = startY + x2;
            int startYPlusX1 = startY + x1;

            // top and bottom horizontal scanlines
            for (int x = startYPlusX1; x <= endOffset; x++) {
                pixels[x] = color; // top horizontal line
                pixels[offset2] = color; // bottom horizontal line
                offset2++;
            }

            // offset2 == endY + x2

            // vertical scanlines
            endOffset = startYPlusX1 + w;
            offset2 -= w;

            for (int y = startY + x2 + w; y < offset2; y += w) {
                pixels[y] = color; // right vertical line
                pixels[endOffset] = color; // left vertical line
                endOffset += w;
            }
        }

        /// <summary>
        /// A Fast Bresenham Type Algorithm For Drawing Ellipses http://homepage.smc.edu/kennedy_john/belipse.pdf 
        /// x2 has to be greater than x1 and y2 has to be greater than y1.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x1">The x-coordinate of the bounding rectangle's left side.</param>
        /// <param name="y1">The y-coordinate of the bounding rectangle's top side.</param>
        /// <param name="x2">The x-coordinate of the bounding rectangle's right side.</param>
        /// <param name="y2">The y-coordinate of the bounding rectangle's bottom side.</param>
        /// <param name="color">The color for the line.</param>
        public static void DrawEllipse(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, Color color) {
            bmp.DrawEllipse(x1, y1, x2, y2, (color.A << 24) | (color.R << 16) | (color.G << 8) | color.B);
        }

        /// <summary>
        /// A Fast Bresenham Type Algorithm For Drawing Ellipses http://homepage.smc.edu/kennedy_john/belipse.pdf 
        /// x2 has to be greater than x1 and y2 has to be greater than y1.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x1">The x-coordinate of the bounding rectangle's left side.</param>
        /// <param name="y1">The y-coordinate of the bounding rectangle's top side.</param>
        /// <param name="x2">The x-coordinate of the bounding rectangle's right side.</param>
        /// <param name="y2">The y-coordinate of the bounding rectangle's bottom side.</param>
        /// <param name="color">The color for the line.</param>
        public static void DrawEllipse(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int color) {
            // Calc center and radius
            int xr = (x2 - x1) >> 1;
            int yr = (y2 - y1) >> 1;
            int xc = x1 + xr;
            int yc = y1 + yr;
            bmp.DrawEllipseCentered(xc, yc, xr, yr, color);
        }

        /// <summary>
        /// A Fast Bresenham Type Algorithm For Drawing Ellipses http://homepage.smc.edu/kennedy_john/belipse.pdf
        /// It uses a different parameter representation than DrawEllipse().
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="xc">The x-coordinate of the ellipses center.</param>
        /// <param name="yc">The y-coordinate of the ellipses center.</param>
        /// <param name="xr">The radius of the ellipse in x-direction.</param>
        /// <param name="yr">The radius of the ellipse in y-direction.</param>
        /// <param name="color">The color for the line.</param>
        public static void DrawEllipseCentered(this WriteableBitmap bmp, int xc, int yc, int xr, int yr, Color color) {
            bmp.DrawEllipseCentered(xc, yc, xr, yr, (color.A << 24) | (color.R << 16) | (color.G << 8) | color.B);
        }

        /// <summary>
        /// A Fast Bresenham Type Algorithm For Drawing Ellipses http://homepage.smc.edu/kennedy_john/belipse.pdf 
        /// It uses a different parameter representation than DrawEllipse().
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="xc">The x-coordinate of the ellipses center.</param>
        /// <param name="yc">The y-coordinate of the ellipses center.</param>
        /// <param name="xr">The radius of the ellipse in x-direction.</param>
        /// <param name="yr">The radius of the ellipse in y-direction.</param>
        /// <param name="color">The color for the line.</param>
        public static void DrawEllipseCentered(this WriteableBitmap bmp, int xc, int yc, int xr, int yr, int color) {
            // Use refs for faster access (really important!) speeds up a lot!
            int w = bmp.PixelWidth;
            int[] pixels = bmp.Pixels;

            // Init vars
            int uh, lh;
            int x = xr;
            int y = 0;
            int xrSqTwo = (xr * xr) << 1;
            int yrSqTwo = (yr * yr) << 1;
            int xChg = yr * yr * (1 - (xr << 1));
            int yChg = xr * xr;
            int err = 0;
            int xStopping = yrSqTwo * xr;
            int yStopping = 0;

            // Draw first set of points counter clockwise where tangent line slope > -1.
            while (xStopping >= yStopping) {
                // Draw 4 quadrant points at once
                uh = (yc + y) * w;            // Upper half
                lh = (yc - y) * w;            // Lower half
                pixels[xc + x + uh] = color;  // Quadrant I
                pixels[xc - x + uh] = color;  // Quadrant II
                pixels[xc - x + lh] = color;  // Quadrant III
                pixels[xc + x + lh] = color;  // Quadrant IV

                y++;
                yStopping += xrSqTwo;
                err += yChg;
                yChg += xrSqTwo;
                if ((xChg + (err << 1)) > 0) {
                    x--;
                    xStopping -= yrSqTwo;
                    err += xChg;
                    xChg += yrSqTwo;
                }
            }

            // ReInit vars
            x = 0;
            y = yr;
            uh = (yc + y) * w;            // Upper half
            lh = (yc - y) * w;            // Lower half
            xChg = yr * yr;
            yChg = xr * xr * (1 - (yr << 1));
            err = 0;
            xStopping = 0;
            yStopping = xrSqTwo * yr;

            // Draw second set of points clockwise where tangent line slope < -1.
            while (xStopping <= yStopping) {
                // Draw 4 quadrant points at once
                pixels[xc + x + uh] = color;  // Quadrant I
                pixels[xc - x + uh] = color;  // Quadrant II
                pixels[xc - x + lh] = color;  // Quadrant III
                pixels[xc + x + lh] = color;  // Quadrant IV

                x++;
                xStopping += yrSqTwo;
                err += xChg;
                xChg += yrSqTwo;
                if ((yChg + (err << 1)) > 0) {
                    y--;
                    uh = (yc + y) * w;            // Upper half
                    lh = (yc - y) * w;            // Lower half
                    yStopping -= xrSqTwo;
                    err += yChg;
                    yChg += xrSqTwo;
                }
            }
        }

        #endregion

        #region Without alpha

        /// <summary>
        /// Sets the color of the pixel using a precalculated index (faster).
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="index">The coordinate index.</param>
        /// <param name="r">The red value of the color.</param>
        /// <param name="g">The green value of the color.</param>
        /// <param name="b">The blue value of the color.</param>
        public static void SetPixeli(this WriteableBitmap bmp, int index, byte r, byte g, byte b) {
            bmp.Pixels[index] = (255 << 24) | (r << 16) | (g << 8) | b;
        }

        /// <summary>
        /// Sets the color of the pixel.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x">The x coordinate (row).</param>
        /// <param name="y">The y coordinate (column).</param>
        /// <param name="r">The red value of the color.</param>
        /// <param name="g">The green value of the color.</param>
        /// <param name="b">The blue value of the color.</param>
        public static void SetPixel(this WriteableBitmap bmp, int x, int y, byte r, byte g, byte b) {
            bmp.Pixels[y * bmp.PixelWidth + x] = (255 << 24) | (r << 16) | (g << 8) | b;
        }

        #endregion

        #region With alpha

        /// <summary>
        /// Sets the color of the pixel including the alpha value and using a precalculated index (faster).
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="index">The coordinate index.</param>
        /// <param name="a">The alpha value of the color.</param>
        /// <param name="r">The red value of the color.</param>
        /// <param name="g">The green value of the color.</param>
        /// <param name="b">The blue value of the color.</param>
        public static void SetPixeli(this WriteableBitmap bmp, int index, byte a, byte r, byte g, byte b) {
            float ai = a * PreMultiplyFactor;
            bmp.Pixels[index] = (a << 24) | ((byte)(r * ai) << 16) | ((byte)(g * ai) << 8) | (byte)(b * ai);
        }

        /// <summary>
        /// Sets the color of the pixel including the alpha value.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x">The x coordinate (row).</param>
        /// <param name="y">The y coordinate (column).</param>
        /// <param name="a">The alpha value of the color.</param>
        /// <param name="r">The red value of the color.</param>
        /// <param name="g">The green value of the color.</param>
        /// <param name="b">The blue value of the color.</param>
        public static void SetPixel(this WriteableBitmap bmp, int x, int y, byte a, byte r, byte g, byte b) {
            float ai = a * PreMultiplyFactor;
            bmp.Pixels[y * bmp.PixelWidth + x] = (a << 24) | ((byte)(r * ai) << 16) | ((byte)(g * ai) << 8) | (byte)(b * ai);
        }

        #endregion

        #region With System.Windows.Media.Color

        /// <summary>
        /// Sets the color of the pixel using a precalculated index (faster).
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="index">The coordinate index.</param>
        /// <param name="color">The color.</param>
        public static void SetPixeli(this WriteableBitmap bmp, int index, Color color) {
            float ai = color.A * PreMultiplyFactor;
            bmp.Pixels[index] = (color.A << 24) | ((byte)(color.R * ai) << 16) | ((byte)(color.G * ai) << 8) | (byte)(color.B * ai);
        }

        /// <summary>
        /// Sets the color of the pixel.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x">The x coordinate (row).</param>
        /// <param name="y">The y coordinate (column).</param>
        /// <param name="color">The color.</param>
        public static void SetPixel(this WriteableBitmap bmp, int x, int y, Color color) {
            float ai = color.A * PreMultiplyFactor;
            bmp.Pixels[y * bmp.PixelWidth + x] = (color.A << 24) | ((byte)(color.R * ai) << 16) | ((byte)(color.G * ai) << 8) | (byte)(color.B * ai);
        }

        /// <summary>
        /// Sets the color of the pixel using an extra alpha value and a precalculated index (faster).
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="index">The coordinate index.</param>
        /// <param name="a">The alpha value of the color.</param>
        /// <param name="color">The color.</param>
        public static void SetPixeli(this WriteableBitmap bmp, int index, byte a, Color color) {
            float ai = a * PreMultiplyFactor;
            bmp.Pixels[index] = (a << 24) | ((byte)(color.R * ai) << 16) | ((byte)(color.G * ai) << 8) | (byte)(color.B * ai);
        }

        /// <summary>
        /// Sets the color of the pixel using an extra alpha value.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x">The x coordinate (row).</param>
        /// <param name="y">The y coordinate (column).</param>
        /// <param name="a">The alpha value of the color.</param>
        /// <param name="color">The color.</param>
        public static void SetPixel(this WriteableBitmap bmp, int x, int y, byte a, Color color) {
            float ai = a * PreMultiplyFactor;
            bmp.Pixels[y * bmp.PixelWidth + x] = (a << 24) | ((byte)(color.R * ai) << 16) | ((byte)(color.G * ai) << 8) | (byte)(color.B * ai);
        }

        /// <summary>
        /// Sets the color of the pixel using a precalculated index (faster).
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="index">The coordinate index.</param>
        /// <param name="color">The color.</param>
        public static void SetPixeli(this WriteableBitmap bmp, int index, int color) {
            bmp.Pixels[index] = color;
        }

        /// <summary>
        /// Sets the color of the pixel.
        /// </summary>
        /// <param name="bmp">The WriteableBitmap.</param>
        /// <param name="x">The x coordinate (row).</param>
        /// <param name="y">The y coordinate (column).</param>
        /// <param name="color">The color.</param>
        public static void SetPixel(this WriteableBitmap bmp, int x, int y, int color) {
            bmp.Pixels[y * bmp.PixelWidth + x] = color;
        }

        #endregion

        #endregion
        //
        #region local message
        /// <summary>
        /// use localmessagesender if you on same one computer you can 
        /// use this method send message to other xaml page or in xap bag .
        /// </summary>
        /// <param name="id">消息的发送与接收通过此id进行匹配</param>
        /// <param name="uri">jump other web page 's uri address</param>
        /// <param name="msg">send message</param>
        /// <param name="xamlPageName">the receiver xaml page 's name.</param>
        public static void SendMessage(string uri, string msg, string id = null, string xamlPageName = "MainPage") {
            if (id == null)
                id = new System.Diagnostics.StackTrace().GetFrame(1).GetMethod().Name;
            var hw = default(System.Windows.Browser.HtmlWindow);
            var sc = System.Threading.SynchronizationContext.Current;
            var lms = new System.Windows.Messaging.LocalMessageSender(id, System.Windows.Messaging.LocalMessageSender.Global);

            var lmr = new System.Windows.Messaging.LocalMessageReceiver("_" + id, System.Windows.Messaging.ReceiverNameScope.Global, System.Windows.Messaging.LocalMessageReceiver.AnyDomain);
            lmr.MessageReceived += (o, k) => {
                lms.SendAsync(msg);
                lmr.Dispose();
            };
            try {
                lmr.Listen();
                hw = System.Windows.Browser.HtmlPage.Window.Navigate(new Uri(uri), xamlPageName);
            } catch {
                lmr.Dispose();
            }
        }
        /// <summary>
        /// 握手通讯，通过对目标页面上加入本方法来实现，页面载入以后的回调，当页面载入以后将发送一个
        /// 空消息，“握手”。然后由发送跳转请求端接收到这个消息以后 握手成功！握手成功以后，发送所需要，数据
        /// 到回调。
        /// </summary>
        /// <param name="id">消息的发送与接收通过此id进行匹配</param>
        /// <param name="call"></param>
        public static void ReceiveMessage(string id, Action<string> call = null) {
            var lmr = new System.Windows.Messaging.LocalMessageReceiver(id, System.Windows.Messaging.ReceiverNameScope.Global, System.Windows.Messaging.LocalMessageReceiver.AnyDomain);
            lmr.MessageReceived += (o, k) => {
                if (call != null) {
                    try {
                        call.Invoke(k.Message);
                    } finally {
                        lmr.Dispose();
                    }
                }
            };
            try {
                lmr.Listen();
                var lms = new System.Windows.Messaging.LocalMessageSender("_" + id, System.Windows.Messaging.LocalMessageSender.Global);
                lms.SendAsync("");
            } catch {
                lmr.Dispose();
            }
        }
        #endregion
        //
        #region framework element
        public static void Independent(this FrameworkElement fe) {
            var p = fe.Parent as Panel;
            if (p != null) {
                p.Children.Remove(fe);
            }
        }
        public static void Dispose(this FrameworkElement fe) {
            var p = fe.Parent as Panel;
            if (p != null) {
                p.Children.Remove(fe);
                fe = null;
            }
        }
        #endregion
        //
        #region json serializer
        static T JsonDeserialise<T>(this string json) {
            T obj = default(T);
            using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json))) {
                var serializer = new DataContractJsonSerializer(typeof(T));
                obj = (T)serializer.ReadObject(ms);
                return obj;
            }
        }
        static string JsonSerialize<T>(this T obj) {
            var serializer = new DataContractJsonSerializer(obj.GetType());
            using (var ms = new MemoryStream()) {
                serializer.WriteObject(ms, obj);
                var json = ms.ToArray();
                return Encoding.UTF8.GetString(json, 0, json.Length);
            }
        }
        #endregion
        //
        #region communicate origin api
        static System.Threading.SynchronizationContext threadContext = System.Threading.SynchronizationContext.Current;
        /// <summary>
        /// 注意只接受json格式的转入序列流
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="rest"></param>
        /// <param name="callback"></param>
        public static void OdataGet<T>(Uri rest, Action<T> callback = null) where T : class {
            var hwr = WebRequest.CreateHttp(rest);
            hwr.Method = "GET";
            hwr.BeginGetResponse(ac => {
                var wr = hwr.EndGetResponse(ac);
                using (var sr = new StreamReader(wr.GetResponseStream())) {
                    var doc = sr.ReadToEnd().Trim();
                    var xdoc = XElement.Parse(doc);
                    var entitys = xdoc.Value.JsonDeserialise<T>();
                    threadContext.Send(sopc => {
                        if (callback != null)
                            callback.Invoke(entitys);
                    }, null);
                }
            }, null);
        }
        /// <summary>
        /// 通过json格式传递的post通讯方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="O"></typeparam>
        /// <param name="rest"></param>
        /// <param name="postdata"></param>
        /// <param name="callback"></param>
        public static void OdataPost<T, O>(Uri rest, T postdata, Action<O> callback = null)
            where T : class
            where O : class {
            var hwr = WebRequest.CreateHttp(rest);
            hwr.Method = "POST";
            hwr.ContentType = "application/x-www-form-urlencoded";
            hwr.BeginGetRequestStream(ac => {
                var hwrp = ac.AsyncState as HttpWebRequest;
                var netstream = hwrp.EndGetRequestStream(ac);
                using (var sw = new StreamWriter(netstream)) {
                    var doc = postdata.JsonSerialize();
                    sw.Write(doc);
                    sw.Flush();
                }
                hwrp.BeginGetResponse(ac2 => {
                    var hwrp2 = ac2.AsyncState as HttpWebRequest;
                    var x = hwrp2.EndGetResponse(ac2);
                    using (var sr = new StreamReader(x.GetResponseStream())) {
                        var doc = sr.ReadToEnd().Trim();
                        var xdoc = XElement.Parse(doc);
                        var o = xdoc.Value.JsonDeserialise<O>();
                        threadContext.Post(sopc => {
                            if (callback != null)
                                callback(sopc as O);
                        }, o);
                    }
                }, hwrp);
            }, hwr);
        }
        //
        /// <summary>
        /// 获取 http get 方法的uri
        /// </summary>
        /// <param name="addressbase"></param>
        /// <param name="methodname"></param>
        /// <param name="ps"></param>
        /// <returns></returns>
        public static Uri GetUri(string addressbase, string methodname, Dictionary<string, object> ps = null) {
            var sb = new StringBuilder(addressbase);
            sb.AppendFormat("/{0}", methodname);
            sb.AppendFormat("?");
            if (ps != null && ps.Count() > 1) {
                foreach (var item in ps) {
                    sb.AppendFormat("&{0}='{1}'", item.Key, item.Value);
                }
            }
            return new Uri(sb.ToString());
        }
        #endregion
    }
}
